#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#define LEARNING_RATE 0.7
#define MAX_ITERACTIONS 1000
#define DATA_SIZE 4
#define DATA_DIM 2

double input[DATA_SIZE][DATA_DIM];
double output[DATA_SIZE];

double weights[DATA_DIM];
double bias;

void
read_data()
{
	input[0][0] = 0;
	input[0][1] = 0;
	output[0] = 0;

	input[1][0] = 0;
	input[1][1] = 1;
	output[1] = 1;

	input[2][0] = 1;
	input[2][1] = 0;
	output[2] = 1;

	input[3][0] = 1;
	input[3][1] = 1;
	output[3] = 1;
}


void
initialize()
{
	int i;

	for (i = 0; i < DATA_DIM; i++)
		weights[i] = (double) rand() / (double) RAND_MAX;
	
	bias = (double) rand() / (double) RAND_MAX;
}


double
sigmoid(double x)
{
	return (1.0 / (1 + exp(-x)));
}


double
run_network(double *data)
{
	int i;
	double out = 0.0;

	for (i = 0; i < DATA_DIM; i++)
		out += (weights[i] * data[i]);

	out += bias;
	return sigmoid(out);
}


void
update_weights(double delta, double *data)
{
	int i;

	for (i = 0; i < DATA_DIM; i++)
	{
		weights[i] = weights[i] + LEARNING_RATE * data[i] * delta;
	}

	bias = bias + LEARNING_RATE * delta;
}


double
train_step()
{
	int i;
	double net_out;
	double error;
	double total_error = 0;

	for (i = 0; i < DATA_SIZE; i++)
	{
		net_out = run_network(input[i]);
		error = (output[i] - net_out);
		update_weights(error, input[i]);
		total_error += fabs(error);
	}

	return total_error;
}


int
convergence_test()
{
	return 0;
}


void
train()
{
	double error;
	int converged = 0;
	int num_iteractions = 0;

	// TODO: train batch
	// TODO: train using inverse

	while (!converged && (num_iteractions < MAX_ITERACTIONS))
	{
		error = train_step();
		converged = convergence_test();
		num_iteractions++;

		fprintf(stderr, "error: %lf\n", error);
	}
}


void
test()
{
	int i;
	double out;

	printf("\nTEST:\n\n");

	for (i = 0; i < DATA_SIZE; i++)
	{
		out = run_network(input[i]);
		printf("%lf %lf = %lf\n", input[i][0], input[i][1], out);
	}
}


int 
main(int argc, char **argv)
{
	read_data();
	initialize();
	train();
	test();

	return 0;
}

